/**
 * 
 */
package com.cmcc.pcap.packet.udp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.cmcc.packet.entity.PfcpEntity;
import com.cmcc.packet.entity.QuicEntity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.cmcc.packet.entity.UdpEntity;
import com.cmcc.pcap.packet.capture.HandlerManager;
import com.cmcc.pcap.packet.capture.JCaptures;


/**
 * @author Amish
 * @date 2018年12月24日 下午3:44:39
 * 
 */
public class UdpProtocolDispatcher implements Runnable{
	public static Logger logger = LogManager.getLogger(UdpProtocolDispatcher.class);
	
    private HashMap<String, UdpProtocolHandler> hashmap;
    JCaptures jCaptures;
	UdpConnectionCache udpConnectionCache;
	private String taskId;

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public UdpProtocolDispatcher(JCaptures jCaptures,UdpConnectionCache udpConnectionCache){
		this.jCaptures = jCaptures;
		this.udpConnectionCache = udpConnectionCache;
		this.hashmap = new HashMap<>();
	}
	
    /**
     * 用于识别UDP的应用层协议，并返回对应的Handler
     * @return
     */
    private UdpProtocolHandler distinguishTcpProtocol(UdpConnection udpConnection){
    	//根据TcpProtocolFilter的结果，直接判断TcpConnection中的对应成员变量
    	switch(udpConnection.protocol){
    	case UDP:{
    		logger.debug("this is return udp handler !");
    		if(hashmap.containsKey("UDP")) {
    			return hashmap.get("UDP");
    		}
    		else {
				try {
					hashmap.put("UDP", HandlerManager.getUdpHandler("udp"));
				} catch (IllegalAccessException | InstantiationException e) {
					logger.error(e.getMessage());
				}
				return hashmap.get("UDP");
    		}
    	}
    	case QUIC:{
			logger.debug("this is return quic handler !");
			if(hashmap.containsKey("QUIC")) {
				return hashmap.get("QUIC");
			}
			else {
				try {
					hashmap.put("QUIC", HandlerManager.getUdpHandler("quic"));
				} catch (IllegalAccessException | InstantiationException e) {
					logger.error(e.getMessage());
				}
				return hashmap.get("QUIC");
			}

    	}

			case PFCP:{
				logger.debug("this is return  pfcp handler !");
				if(hashmap.containsKey("PFCP")) {
					return hashmap.get("PFCP");
				}
				else {
					try {
						hashmap.put("PFCP", HandlerManager.getUdpHandler("pfcp"));
					} catch (IllegalAccessException | InstantiationException e) {
						logger.error(e.getMessage());
					}
					return hashmap.get("PFCP");
				}
			}

    	default:
    		logger.info("Can not dispatcher protocol : "+udpConnection.protocol.name());
    		return null;
    	}
    }

	@Override
	public void run() {
		
		while(true){
			
			ArrayList<UdpConnection> al  = this.udpConnectionCache.getUdpConnection();//此处由于同步 可能阻塞
            if(al.size() != 0){
            	logger.debug("Get Udp Connection num : "+al.size());
            }
			for(UdpConnection udpConnection : al){
				try{
					UdpProtocolHandler udpProtocolHandler = distinguishTcpProtocol(udpConnection);
					if (udpProtocolHandler != null) {
						String protocolStr= udpProtocolHandler.getClass().toString();
						String protocolString=protocolStr.substring(protocolStr.lastIndexOf(".")+1);
						if(protocolString.equals("UdpHandler")) {
							List<UdpEntity> xdrList = udpProtocolHandler.handle(udpConnection,taskId);
							if(xdrList!=null&&xdrList.size()!=0) {
								jCaptures.udpcallBack.action(xdrList);
							}
						}
						if(protocolString.equals("QuicHandler")) {
							List<QuicEntity> xdrList = udpProtocolHandler.handle(udpConnection,taskId);
							if(xdrList!=null&&xdrList.size()!=0) {
								jCaptures.quicCallBack.action(xdrList);
							}
						}
						if(protocolString.equals("PfcpHandler")) {
							List<PfcpEntity> xdrList = udpProtocolHandler.handle(udpConnection,taskId);
							if(xdrList!=null&&xdrList.size()!=0) {
								jCaptures.pfcpcallBack.action(xdrList);
							}
						}
					}else{
						logger.error("Can not get the protocol handler");
					}
					
				}catch(Exception e){
					logger.error(e.getCause(),e);
				}finally {
					udpConnectionCache.handledPacketNum.addAndGet(udpConnection.al.size());
				}
			}
		}
	}

}
